#include <stdio.h>
#include <error.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <limits.h>
#include <poll.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <time.h>
#include <list>
#include <arpa/inet.h>
#include <assert.h>

#define BUF_SIZE            1024                //默认缓冲区
#define SERVER_PORT         8888                //监听端口
#define SERVER_HOST         "127.0.0.1"         //服务器IP地址
#define EPOLL_RUN_TIMEOUT   -1                  //epoll的超时时间
#define MAX_EVENT_NUMBER 	1                   //epoll监听的客户端的最大数目

#define STR_WELCOME "Welcome to seChat! You ID is: Client #%d"
#define STR_MESSAGE "Client #%d>> %s"
#define STR_NOONE_CONNECTED "Noone connected to server except you!"
#define CMD_EXIT "EXIT"

/**
 * 添加epoll事件
 */
void addevent(int epollfd, int fd, int event)
{
    epoll_event ev;
    ev.data.fd = fd;    // 需要监控的文件描述符

    switch (event)
    {
        case 0:
            ev.events = EPOLLIN;            // 添加监控事件，读
            break;
        case 1:
            ev.events = EPOLLIN|EPOLLET;    // 添加监控事件，读+ET
            break;
        default:
            break;
    }

    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
    // 设置非阻塞
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
}

void rmevent(int epollfd, int fd)
{
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, NULL);
    close(fd);
}

char * parse_content()
{
    return NULL;
}

char * current_datetime()
{
    char *fmt_time;
    time_t nowtime;
    time(&nowtime);                 //获取1900年1月1日0点0分0秒到现在经过的秒数
    tm* p = localtime(&nowtime);    //将秒数转换为本地时间,年从1900算起,需要+1900,月为0-11,所以要+1
    sprintf(fmt_time,"%04d:%02d:%02d %02d %02d %02d", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
    
    //printf("%04d:%02d:%02d %02d %02d %02d\n", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
    return fmt_time;
}

int main(int argc, char **argv)
{

    int listenfd;
    struct sockaddr_in addr;

    addr.sin_family = AF_INET;
    addr.sin_port = htons(SERVER_PORT);
    //addr.sin_addr.s_addr = inet_addr(SERVER_HOST);
    addr.sin_addr.s_addr = INADDR_ANY;

    listenfd = socket(PF_INET, SOCK_STREAM, 0);
    assert(listenfd >= 0);

    int ret = bind(listenfd, (struct sockaddr *)&addr, sizeof(addr));
    assert(ret != -1);

    /**
     * 服务器监听时，在每次处理一个客户端的连接时是需要一定时间的，这个时间非常的短(也许只有1ms 或者还不到)，但这个时间还是存在的。而这个backlog 存在的意义就是：在这段时间里面除了第一个连接请求是正在进行处理以外，其他的连接请求都在请求队列中等待，而如果超过了队列的最大等待个数时，其他的请求将被忽略或者将不会被处理。这个backlog 的值就是影响这个队列的大小的。
     */
    ret = listen(listenfd, 64);
    assert(ret != -1);
    
    struct epoll_event events[MAX_EVENT_NUMBER];
    /**
     * epoll_create 的参数size表示是要指定这个epoll实例可以监控的最大的套接字个数，但是在 Linux 2.6.8 内核版本以后，这个参数内核已经不再处理了（就是没有限制了），但是必须要大于1。
     */
    int epollfd = epoll_create(8);
    
    //LT+LT
    addevent(epollfd, listenfd, 0);

    char *buff;
    int BUFF_SIZE = 8;

    while (true)
    {
        printf("%s\n", "epoll_wait------------");
        int ev  = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, EPOLL_RUN_TIMEOUT);
        printf("%s:%d\n", "event", ev);
        if(ev > 0)
        {
            for(int i=0; i<ev; i++)
            {
                int sockfd = events[i].data.fd;
                if(sockfd == listenfd)  // 来自客户端的新连接，此时开始添加对连接的监控
                {
                    
                    printf("%s\n", "client is connected!");

                    struct sockaddr_in client_addr;
                    socklen_t socklen = sizeof(client_addr);
                    int clientfd = accept(listenfd, (struct sockaddr *)&client_addr, &socklen);
                    
                    addevent(epollfd, clientfd, 0);

                }
                else if(events[i].events & EPOLLIN)    // 处理读事件
                {
                    printf("%s:%d\n", "sockfd", sockfd);
                    bool is_close = false;
                    int read_len = 0;
                    // 读取数据
                    while (true)
                    {
                        // 不断的向buff添加BUFF_SIZE个数据
                        int len = recv(sockfd, buff + read_len, sizeof(BUFF_SIZE), 0);
                        if(len < 0)
                        {
                            if(errno == EAGAIN || errno == EWOULDBLOCK)
                            {
                                printf("%s:%s\n", "buff", buff);
                                printf("%s\n", "send data to client!");
                                break;
                            }
                            else
                            {
                                printf("%s:%d\n", "errno",errno);
                            }
                            break;
                        }
                        else if(len > 0)
                        {
                            // 继续读取
                            //printf("%s:%s\n", "buff", buff);
                        }
                        else
                        {
                            printf("%s\n", "client closed!");
                            is_close = true;
                            // len == 0 关闭连接
                            rmevent(epollfd, sockfd);
                            break;
                        }
                        read_len += len;
                    }
                    if(is_close)
                    {
                        continue;
                    }

                    // 解析数据(HTTP)

                    // 响应数据
                    send(sockfd, buff, sizeof(buff), 0);
                    
                    // 关闭数据
                    rmevent(epollfd, sockfd);
                    printf("%s\n", "client closed!");

                }
            }
        }
        
    }
    
    close(listenfd);
    close(epollfd);
    
    return 0;
}